use crate::storage::Status::{Completed, Pending};
use anyhow::Result;
use chrono::{NaiveDate, NaiveDateTime};

pub mod storage;

#[derive(Debug)]
pub struct TodoItem {
    pub id: u32,
    pub content: String,
    pub status: u8,
    pub date: NaiveDate,
    pub completed_at: Option<NaiveDateTime>,
    pub priority: u8,
    pub created_at: Option<NaiveDateTime>,
    // 优先级的最后更新时间
    pub priority_updated_at: Option<NaiveDateTime>,
    pub updated_at: Option<NaiveDateTime>,
}

pub trait Storage {
    fn insert(&self, todo: &InsertTodoItem) -> Result<i32>;

    fn select(&self, date: &NaiveDate, status: &Option<Status>) -> Result<Vec<TodoItem>>;

    fn cp(&self, id: u32) -> Result<u32>;

    fn find_by_id(&self, id: u32) -> Result<Option<TodoItem>>;

    fn update_date(&self, id: u32, date: &NaiveDate) -> Result<()>;

    fn delete_by_id(&self, id: u32) -> Result<()>;

    fn delete_by_date(&self, date: &NaiveDate) -> Result<()>;

    fn update(&self, update: &UpdateTodoItem) -> Result<()>;

    fn update_status(&self, id: u32, status: Status, top_priority: Option<bool>) -> Result<()>;

    fn clear(&self) -> Result<()>;
}

#[derive(Debug)]
pub struct InsertTodoItem {
    pub content: String,
    pub date: NaiveDate,
    pub priority: u8,
}

#[derive(Debug, Clone)]
pub enum Status {
    Completed,
    Pending,
}

#[derive(Debug)]
pub struct UpdateTodoItem {
    pub id: u32,

    pub content: Option<String>,

    pub top_priority: Option<bool>,

    pub date: Option<NaiveDate>,
}

impl From<u8> for Status {
    fn from(value: u8) -> Self {
        match value {
            1 => Completed,
            _ => Pending
        }
    }
}

impl From<u8> for &Status {
    fn from(value: u8) -> Self {
        match value {
            1 => &Completed,
            _ => &Pending,
        }
    }
}

impl From<Status> for u8 {
    fn from(value: Status) -> Self {
        match value {
            Completed => 1,
            Pending => 0,
        }
    }
}

impl From<&Status> for u8 {
    fn from(value: &Status) -> Self {
        match value {
            Completed => 1,
            Pending => 0,
        }
    }
}